home *** CD-ROM | disk | FTP | other *** search
/ Hand Picked Software / Hand Picked Software.iso / aids / ar110 / ar.c < prev    next >
C/C++ Source or Header  |  1995-03-13  |  12KB  |  450 lines

  1. /***********************************************************
  2.     ar.c -- main file
  3. ***********************************************************/
  4.  
  5. static char *usage =
  6.     "ar -- compression archiver -- written by Haruhiko Okumura\n"
  7.     "                        modifications by Terran Melconian\n\n"
  8.     "Usage: ar command archive [file ...]\n"
  9.     "Commands:\n"
  10.     "   a: Add files to archive (replace if present)\n"
  11.     "   e: Extract files from archive\n"
  12.     "   x: Extract files with path\n"
  13.     "   r: Replace files in archive\n"
  14.     "   d: Delete files from archive\n"
  15.     "   p: Print files on standard output\n"
  16.     "   l: List contents of archive\n"
  17.     "If no files are named, all files in archive are processed,\n"
  18.     "   except for commands 'a' and 'd'.\n"
  19.     "You may copy, distribute, and rewrite this program freely.\n";
  20.  
  21. /***********************************************************
  22.  
  23. Structure of archive block (low order byte first):
  24. -----preheader
  25.  1    basic header size
  26.         = 25 + strlen(filename) (= 0 if end of archive)
  27.  1    basic header algebraic sum (mod 256)
  28. -----basic header
  29.  5    method ("-lh0-" = stored, "-lh5-" = compressed)
  30.  4    compressed size (including extended headers)
  31.  4    original size
  32.  4    not used
  33.  1    0x20
  34.  1    0x01
  35.  1    filename length (x)
  36.  x    filename
  37.  2    original file's CRC
  38.  1    0x20
  39.  2    first extended header size (0 if none)
  40. -----first extended header, etc.
  41. -----compressed file
  42.  
  43. ***********************************************************/
  44.  
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <ctype.h>
  48. #include <dir.h>
  49. #include "ar.h"
  50.  
  51. #define FNAME_MAX (255 - 25) /* max strlen(filename) */
  52. #define namelen  header[19]
  53. #define filename ((char *)&header[20])
  54.  
  55. int unpackable;            /* global, set in io.c */
  56. ulong compsize, origsize;  /* global */
  57.  
  58. static uchar buffer[DICSIZ];
  59. static uchar header[255];
  60. static uchar headersize, headersum;
  61. static uint  file_crc;
  62. static char  *temp_name;
  63.  
  64. static uint ratio(ulong a, ulong b)  /* [(1000a + [b/2]) / b] */
  65. {
  66.     int i;
  67.  
  68.     for (i = 0; i < 3; i++)
  69.         if (a <= ULONG_MAX / 10) a *= 10;  else b /= 10;
  70.     if ((ulong)(a + (b >> 1)) < a) {  a >>= 1;  b >>= 1;  }
  71.     if (b == 0) return 0;
  72.     return (uint)((a + (b >> 1)) / b);
  73. }
  74.  
  75. static void put_to_header(int i, int n, ulong x)
  76. {
  77.     while (--n >= 0) {
  78.         header[i++] = (uchar)((uint)x & 0xFF);  x >>= 8;
  79.     }
  80. }
  81.  
  82. static ulong get_from_header(int i, int n)
  83. {
  84.     ulong s;
  85.  
  86.     s = 0;
  87.     while (--n >= 0) s = (s << 8) + header[i + n];  /* little endian */
  88.     return s;
  89. }
  90.  
  91. static uint calc_headersum(void)
  92. {
  93.     int i;
  94.     uint s;
  95.  
  96.     s = 0;
  97.     for (i = 0; i < headersize; i++) s += header[i];
  98.     return s & 0xFF;
  99. }
  100.  
  101. static int read_header(void)
  102. {
  103.     headersize = (uchar) fgetc(arcfile);
  104.     if (headersize == 0) return 0;  /* end of archive */
  105.     headersum  = (uchar) fgetc(arcfile);
  106.     fread_crc(header, headersize, arcfile);  /* CRC not used */
  107.     if (calc_headersum() != headersum) error("Header sum error");
  108.     compsize = get_from_header(5, 4);
  109.     origsize = get_from_header(9, 4);
  110.     file_crc = (uint)get_from_header(headersize - 5, 2);
  111.     filename[namelen] = '\0';
  112.     return 1;  /* success */
  113. }
  114.  
  115. static void write_header(void)
  116. {
  117.     fputc(headersize, outfile);
  118.     /* We've destroyed file_crc by null-terminating filename. */
  119.     put_to_header(headersize - 5, 2, (ulong)file_crc);
  120.     fputc(calc_headersum(), outfile);
  121.     fwrite_crc(header, headersize, outfile);  /* CRC not used */
  122. }
  123.  
  124. static void skip(void)
  125. {
  126.     fseek(arcfile, compsize, SEEK_CUR);
  127. }
  128.  
  129. static void copy(void)
  130. {
  131.     uint n;
  132.  
  133.     write_header();
  134.     while (compsize != 0) {
  135.         n = (uint)((compsize > DICSIZ) ? DICSIZ : compsize);
  136.         if (fread ((char *)buffer, 1, n, arcfile) != n)
  137.             error("Can't read");
  138.         if (fwrite((char *)buffer, 1, n, outfile) != n)
  139.             error("Can't write");
  140.         compsize -= n;
  141.     }
  142. }
  143.  
  144. static void store(void)
  145. {
  146.     uint n;
  147.  
  148.     origsize = 0;
  149.     crc = INIT_CRC;
  150.     while ((n = fread((char *)buffer, 1, DICSIZ, infile)) != 0) {
  151.         fwrite_crc(buffer, n, outfile);  origsize += n;
  152.     }
  153.     compsize = origsize;
  154. }
  155.  
  156. static int add(int replace_flag)
  157. {
  158.     long headerpos, arcpos;
  159.     uint r;
  160.  
  161.     if ((infile = fopen(filename, "rb")) == NULL) {
  162.         fprintf(stderr, "Can't open %s\n", filename);
  163.         return 0;  /* failure */
  164.     }
  165.     if (replace_flag) {
  166.         printf("Replacing %-20s ", filename);  skip();
  167.     } else
  168.         printf("Adding %-23s ", filename);
  169.     headerpos = ftell(outfile);
  170.     namelen = strlen(filename);
  171.     headersize = 25 + namelen;
  172.     memcpy(header, "-lh5-", 5);  /* compress */
  173.     write_header();  /* temporarily */
  174.     arcpos = ftell(outfile);
  175.     origsize = compsize = 0;  unpackable = 0;
  176.     crc = INIT_CRC;  encode();
  177.     if (unpackable) {
  178.         header[3] = '0';  /* store */
  179.         rewind(infile);
  180.         fseek(outfile, arcpos, SEEK_SET);
  181.         store();
  182.     }
  183.     file_crc = crc ^ INIT_CRC;
  184.     fclose(infile);
  185.     put_to_header(5, 4, compsize);
  186.     put_to_header(9, 4, origsize);
  187.     memcpy(header + 13, "\0\0\0\0\x20\x01", 6);
  188.     memcpy(header + headersize - 3, "\x20\0\0", 3);
  189.     fseek(outfile, headerpos, SEEK_SET);
  190.     write_header();  /* true header */
  191.     fseek(outfile, 0L, SEEK_END);
  192.     r = ratio(compsize, origsize);
  193. //    gotoxy (40, wherey());
  194.     printf(" %d.%d%%\n", r / 10, r % 10);
  195.     return 1;  /* success */
  196. }
  197.  
  198. int get_line(char *s, int n)
  199. {
  200.     int i, c;
  201.  
  202.     i = 0;
  203.     while ((c = getchar()) != EOF && c != '\n')
  204.         if (i < n) s[i++] = (char)c;
  205.     s[i] = '\0';
  206.     return i;
  207. }
  208.  
  209. static void extract(int to_file)
  210. {
  211.     int n, m, method;
  212.     uint ext_headersize;
  213.  
  214.     if (to_file == 2)
  215.     {
  216.         m=0;
  217.         n=0;
  218.         while (filename[n] != 0)
  219.         {
  220.             if (m==12)
  221.                 m=0;
  222.             filename[m]=filename[n];
  223.             if (filename[m] == '\\')
  224.                 m=-1;
  225.             m++;
  226.             n++;
  227.         }
  228.         filename[m]=0;
  229.     }
  230.  
  231.  
  232.     if (to_file) {
  233.         while ((outfile = fopen(filename, "wb")) == NULL) {
  234.             fprintf(stderr, "Can't open %s\nNew filename: ", filename);
  235.             if (get_line(filename, FNAME_MAX) == 0) {
  236.                 fprintf(stderr, "Not extracted\n");
  237.                 skip();  return;
  238.             }
  239.             namelen = strlen(filename);
  240.         }
  241.         printf("Extracting %s ", filename);
  242.     } else {
  243.         outfile = stdout;
  244.         printf("===== %s =====\n", filename);
  245.     }
  246.     crc = INIT_CRC;
  247.     method = header[3];  header[3] = ' ';
  248.     if (! strchr("045", method) || memcmp("-lh -", header, 5)) {
  249.         fprintf(stderr, "Unknown method: %u\n", method);
  250.         skip();
  251.     } else {
  252.         ext_headersize = (uint)get_from_header(headersize - 2, 2);
  253.         while (ext_headersize != 0) {
  254.             fprintf(stderr, "There's an extended header of size %u.\n",
  255.                 ext_headersize);
  256.             compsize -= ext_headersize;
  257.             if (fseek(arcfile, ext_headersize - 2, SEEK_CUR))
  258.                 error("Can't read");
  259.             ext_headersize = fgetc(arcfile);
  260.             ext_headersize += (uint)fgetc(arcfile) << 8;
  261.         }
  262.         crc = INIT_CRC;
  263.         if (method != '0') decode_start();
  264.         while (origsize != 0) {
  265.             n = (uint)((origsize > DICSIZ) ? DICSIZ : origsize);
  266.             if (method != '0') decode(n, buffer);
  267.             else if (fread((char *)buffer, 1, n, arcfile) != n)
  268.                 error("Can't read");
  269.             fwrite_crc(buffer, n, outfile);
  270.             if (outfile != stdout) putc('.', stderr);
  271.             origsize -= n;
  272.         }
  273.     }
  274.     if (to_file) fclose(outfile);  else outfile = NULL;
  275.     printf("\n");
  276.     if ((crc ^ INIT_CRC) != file_crc)
  277.         fprintf(stderr, "CRC error\n");
  278. }
  279.  
  280. static void list_start(void)
  281. {
  282.     printf("Filename             Original Compressed Ratio CRC Method\n");
  283. }
  284.  
  285. static void list(void)
  286. {
  287.     uint r;
  288.  
  289.     printf("%-18s", filename);
  290.     if (namelen > 18) printf("\n                  ");
  291.     r = ratio(compsize, origsize);
  292.     printf(" %10lu %10lu %u.%03u %04X %5.5s\n",
  293.         origsize, compsize, r / 1000, r % 1000, file_crc, header);
  294. }
  295.  
  296. static int match(char *s1, char *s2)
  297. {
  298.     for ( ; ; ) {
  299.         while (*s2 == '*' || *s2 == '?') {
  300.             if (*s2++ == '*')
  301.                 while (*s1 && *s1 != *s2) s1++;
  302.             else if (*s1 == 0)
  303.                 return 0;
  304.             else s1++;
  305.         }
  306.         if (*s1 != *s2) return 0;
  307.         if (*s1 == 0  ) return 1;
  308.         s1++;  s2++;
  309.     }
  310. }
  311.  
  312. static int search(int argc, char *argv[])
  313. {
  314.     int i;
  315.  
  316.     if (argc == 3) return 1;
  317.     for (i = 3; i < argc; i++)
  318.         if (match(filename, argv[i])) return 1;
  319.     return 0;
  320. }
  321.  
  322. static void exitfunc(void)
  323. {
  324.     fclose(outfile);  remove(temp_name);
  325. }
  326.  
  327. int main(int argc, char *argv[])
  328. {
  329.     int i, j, cmd, count, nfiles, found, done;
  330.     char arcname[12];
  331.     struct ffblk *foundfile;
  332.  
  333.     /* Check command line arguments. */
  334.     if (argc < 3
  335.      || argv[1][1] != '\0'
  336.      || ! strchr("AEXRDPL", cmd = toupper(argv[1][0]))
  337.      || (argc == 3 && strchr("AD", cmd)))
  338.         error(usage);
  339.  
  340.     /* Wildcards used? */
  341.     for (i = 3; i < argc; i++)
  342.         if (strpbrk(argv[i], "*?")) break;
  343.     if (i < argc) nfiles = -1;  /* contains wildcards */
  344.     else nfiles = argc - 3;     /* number of files to process */
  345.  
  346.     /* Make everything Upper-Case */
  347.     for (i=argc-1; i>=3; i--)
  348.         for (j=0; argv[i][j]!=0; j++)
  349.             argv[i][j]=toupper(argv[i][j]);
  350.  
  351.  
  352.     /* Add .AR extention if no extention specified */
  353.     j=0;
  354.     for (i=0; i<12; i++)
  355.     {
  356.         arcname[i]=argv[2][i];
  357.         if (arcname[i]=='.')
  358.             j=1;
  359.         if (arcname[i]==0)
  360.             break;
  361.     }
  362.     if (!j)
  363.         strcat(arcname, ".AR");
  364.  
  365.     /* Open archive. */
  366.     arcfile = fopen(arcname, "rb");
  367.     if (arcfile == NULL && cmd != 'A')
  368.         error("Can't open archive '%s'", arcname);
  369.  
  370.     /* Open temporary file. */
  371.     if (strchr("ARD", cmd)) {
  372.         temp_name = tmpnam(NULL);
  373.         outfile = fopen(temp_name, "wb");
  374.         if (outfile == NULL)
  375.             error("Can't open temporary file");
  376.         atexit(exitfunc);
  377.     } else temp_name = NULL;
  378.  
  379.     make_crctable();  count = done = 0;
  380.  
  381.     if (cmd == 'A') {
  382.         for (i = 3; i < argc; i++) {
  383.             for (j = 3; j < i; j++)
  384.                 if (strcmp(argv[j], argv[i]) == 0) break;
  385.             if (j == i) {
  386.                 char path[30];
  387.                 int k,l;
  388.                 for (k=strlen(argv[i])-1; k>=0; k--)
  389.                     if (argv[i][k] == '\\')
  390.                         break;
  391.  
  392.                 for (l=0; l<=k; l++)
  393.                     path[l]=toupper(argv[i][l]);
  394.                 path[l]=0;
  395.  
  396.                 findfirst (argv[i], foundfile, 0);
  397.                 strcpy(filename, path);
  398.                 strcat(filename, foundfile->ff_name);
  399.                 if (add(0)) count++;  else argv[i][0] = 0;
  400.                 while (!findnext(foundfile))
  401.                 {
  402.                     strcpy(filename, path);
  403.                     strcat(filename, foundfile->ff_name);
  404.                     if (add(0)) count++;  else argv[i][0] = 0;
  405.                 }
  406.             } else nfiles--;
  407.         }
  408.         if (count == 0 || arcfile == NULL) done = 1;
  409.     }
  410.  
  411.     while (! done && read_header()) {
  412.         found = search(argc, argv);
  413.         switch (cmd) {
  414.         case 'R':
  415.             if (found) {
  416.                 if (add(1)) count++;  else copy();
  417.             } else copy();
  418.             break;
  419.         case 'A':  case 'D':
  420.             if (found) {
  421.                 count += (cmd == 'D');  skip();
  422.             } else copy();
  423.             break;
  424.         case 'X':  case 'P':  case 'E':
  425.             if (found) {
  426.                 extract((cmd == 'X') + 2*(cmd == 'E'));
  427.                 if (++count == nfiles) done = 1;
  428.             } else skip();
  429.             break;
  430.         case 'L':
  431.             if (found) {
  432.                 if (count == 0) list_start();
  433.                 list();
  434.                 if (++count == nfiles) done = 1;
  435.             }
  436.             skip();  break;
  437.         }
  438.     }
  439.  
  440.     if (temp_name != NULL && count != 0) {
  441.         fputc(0, outfile);  /* end of archive */
  442.         if (ferror(outfile) || fclose(outfile) == EOF)
  443.             error("Can't write");
  444.         remove(arcname);  rename(temp_name, arcname);
  445.     }
  446.  
  447.     printf("  %d files\n", count);
  448.     return EXIT_SUCCESS;
  449. }
  450.